home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume18 / elm2.2 / part15 < prev    next >
Encoding:
Internet Message Format  |  1989-04-12  |  49.4 KB

  1. Subject:  v18i094:  Elm mail system, release 2.2, Part15/24
  2. Newsgroups: comp.sources.unix
  3. Sender: sources
  4. Approved: rsalz@uunet.UU.NET
  5.  
  6. Submitted-by: dsinc!syd@uunet.UU.NET (Syd Weinstein)
  7. Posting-number: Volume 18, Issue 94
  8. Archive-name: elm2.2/part15
  9.  
  10. #!/bin/sh
  11. # this is part 15 of a multipart archive
  12. # do not concatenate these parts, unpack them in order with /bin/sh
  13. # file src/forms.c continued
  14. #
  15. CurArch=15
  16. if test ! -r s2_seq_.tmp
  17. then echo "Please unpack part 1 first!"
  18.      exit 1; fi
  19. ( read Scheck
  20.   if test "$Scheck" != $CurArch
  21.   then echo "Please unpack part $Scheck next!"
  22.        exit 1;
  23.   else exit 0; fi
  24. ) < s2_seq_.tmp || exit 1
  25. echo "x - Continuing file src/forms.c"
  26. sed 's/^X//' << 'SHAR_EOF' >> src/forms.c
  27. X}
  28. X
  29. Xint
  30. Xmail_filled_in_form(address, subject)
  31. Xchar *address, *subject;
  32. X{
  33. X    /** This is the interesting routine.  This one will read the
  34. X        message and prompt the user, line by line, for each of
  35. X        the fields...returns non-zero if it succeeds
  36. X    **/
  37. X
  38. X    FILE           *fd;
  39. X    register int lines = 0, count;
  40. X    char         buffer[SLEN], *ptr;
  41. X
  42. X    dprint(4, (debugfile, 
  43. X        "replying to form with;\n\taddress=%s and\n\t subject=%s\n",
  44. X         address, subject));
  45. X
  46. X        if (fseek(mailfile, headers[current-1]->offset, 0) == -1) {
  47. X      dprint(1, (debugfile,
  48. X           "Error: seek %ld resulted in errno %s (%s)\n", 
  49. X           headers[current-1]->offset, error_name(errno), 
  50. X           "mail_filled_in_form"));
  51. X      error2("ELM [seek] couldn't read %d bytes into file (%s).",
  52. X             headers[current-1]->offset, error_name(errno));
  53. X      return(0);
  54. X        }
  55. X    /* now we can fly along and get to the message body... */
  56. X
  57. X    while ((ptr = fgets(buffer, SLEN, mailfile)) != NULL) {
  58. X      if (strlen(buffer) == 1)    /* <return> only */
  59. X        break;
  60. X      else if (strncmp(buffer,"From ", 5) == 0 && lines++ > 0) {
  61. X        error("No form in this message!?");
  62. X        return(0);
  63. X      }
  64. X    }
  65. X
  66. X    if (ptr == NULL) {
  67. X      error("No form in this message!?");
  68. X      return(0);
  69. X    }
  70. X
  71. X    dprint(6, (debugfile, "- past header of form message -\n"));
  72. X    
  73. X    /* at this point we're at the beginning of the body of the message */
  74. X
  75. X    /* now we can skip to the FORM-IMAGE section by reading through a 
  76. X       line with a triple asterisk... */
  77. X
  78. X    while ((ptr = fgets(buffer, SLEN, mailfile)) != NULL) {
  79. X      if (strcmp(buffer, "***\n") == 0)
  80. X        break;    /* we GOT it!  It's a miracle! */    
  81. X      else if (strncmp(buffer, "From ",5) == 0) {
  82. X        error("Badly constructed form.  Can't reply!");
  83. X        return(0);
  84. X      }
  85. X    }
  86. X
  87. X    if (ptr == NULL) {
  88. X      error("Badly constructed form.  Can't reply!");
  89. X      return(0);
  90. X    }
  91. X
  92. X    dprint(6, (debugfile, "- skipped the non-forms-image stuff -\n"));
  93. X    
  94. X    /* one last thing - let's open the tempfile for output... */
  95. X    
  96. X    sprintf(buffer, "%s%d", temp_form_file, getpid());
  97. X
  98. X    dprint(2, (debugfile,"-- forms sending using file %s --\n", buffer));
  99. X
  100. X    if ((fd = fopen(buffer,"w")) == NULL) {
  101. X      error2("Can't open \"%s\" as output file! (%s).", buffer,
  102. X         error_name(errno));
  103. X      dprint(1, (debugfile,
  104. X          "** Error %s encountered trying to open temp file %s;\n",
  105. X          error_name(errno), buffer));
  106. X      return(0);
  107. X    }
  108. X
  109. X    /* NOW we're ready to read the form image in and start prompting... */
  110. X
  111. X    Raw(OFF);
  112. X    ClearScreen();
  113. X
  114. X    while ((ptr = fgets(buffer, SLEN, mailfile)) != NULL) {
  115. X      dprint(9, (debugfile, "- read %s", buffer));
  116. X      if (strcmp(buffer, "***\n") == 0) /* end of form! */
  117. X        break;
  118. X     
  119. X      switch ((count = occurances_of(COLON, buffer))) {
  120. X        case 0 : printf("%s", buffer);        /* output line */
  121. X             fprintf(fd, "%s", buffer);     
  122. X             break;
  123. X            case 1 : if (buffer[0] == COLON) {
  124. X                 printf(
  125. X"(Enter as many lines as needed, ending with a '.' by itself on a line)\n");
  126. X                     while (fgets(buffer, SLEN, stdin) != NULL)
  127. X               no_ret(buffer);
  128. X                   if (strcmp(buffer, ".") == 0)
  129. X                     break;
  130. X                   else 
  131. X             fprintf(fd,"%s\n", buffer);
  132. X                 }
  133. X                 else 
  134. X               prompt_for_entry(buffer, fd);
  135. X                 break;
  136. X            default: prompt_for_multiple_entries(buffer, fd, count);
  137. X      }
  138. X    }
  139. X
  140. X    Raw(ON);
  141. X    fclose(fd);
  142. X
  143. X    /** let's just mail this off now... **/
  144. X
  145. X    mail_form(address, subject);
  146. X
  147. X    return(1);
  148. X}
  149. X
  150. Xprompt_for_entry(buffer, fd)
  151. Xchar *buffer;
  152. XFILE *fd;
  153. X{
  154. X    /** This is called with an entry of the form "prompt:" and will 
  155. X        display the prompt and save the prompt and the user reply
  156. X        in the file "fd"
  157. X    **/
  158. X    
  159. X    char mybuffer[SLEN];
  160. X
  161. X    no_ret(buffer);
  162. X
  163. X    dprint(7, (debugfile, "prompt-for-entry \"%s\"\n", buffer));
  164. X
  165. X    printf("%s ", buffer);    fflush(stdout);
  166. X
  167. X    fgets(mybuffer, SLEN, stdin);
  168. X
  169. X    fprintf(fd, "%s: %s", buffer, mybuffer);
  170. X}
  171. X
  172. Xprompt_for_multiple_entries(buffer, fd, entries)
  173. Xchar *buffer;
  174. XFILE *fd;
  175. Xint  entries;
  176. X{
  177. X    /** Almost the same as the above routine, this one deals with lines
  178. X        that have multiple colons on them.  It must first figure out how
  179. X        many spaces to allocate for each field then prompts the user, 
  180. X        line by line, for the entries...
  181. X    **/
  182. X
  183. X    char mybuffer[SLEN], prompt[SLEN], spaces[SLEN];
  184. X    register int  field_size, i, j, offset = 0, extra_tabs = 0;
  185. X
  186. X    dprint(7, (debugfile, 
  187. X        "prompt-for-multiple [%d] -entries \"%s\"\n", entries,
  188. X        buffer));
  189. X
  190. X    strcpy(prompt, "No Prompt Available:");
  191. X
  192. X    while (entries--) {
  193. X      j=0; 
  194. X      i = chloc((char *) buffer + offset, COLON) + 1;
  195. X      while (j < i - 1) {
  196. X        prompt[j] = buffer[j+offset];
  197. X        j++;
  198. X      }
  199. X      prompt[j] = '\0';
  200. X
  201. X      field_size = 0;
  202. X
  203. X      while (whitespace(buffer[i+offset])) {
  204. X        if (buffer[i+offset] == TAB) {
  205. X          field_size += 8 - (i % 8);
  206. X          extra_tabs += (8 - (i % 8)) - 1;
  207. X        }
  208. X        else
  209. X          field_size += 1;
  210. X        i++;
  211. X      }
  212. X
  213. X      offset += i;
  214. X    
  215. X      if (field_size == 0)     /* probably last prompt in line... */
  216. X        field_size = 80 - (offset + extra_tabs);
  217. X
  218. X      prompt_for_sized_entry(prompt, mybuffer, field_size);
  219. X
  220. X      spaces[0] = ' ';    /* always at least ONE trailing space... */
  221. X      spaces[1] = '\0';
  222. X
  223. X      for (j = strlen(mybuffer); j < field_size; j++)
  224. X        strcat(spaces, " ");
  225. X
  226. X      fprintf(fd, "%s: %s%s", prompt, mybuffer, spaces);
  227. X      fflush(fd);
  228. X    }
  229. X
  230. X    fprintf(fd, "\n");
  231. X}
  232. X
  233. Xprompt_for_sized_entry(prompt, buffer, field_size)
  234. Xchar *prompt, *buffer;
  235. Xint   field_size;
  236. X{
  237. X    /* This routine prompts for an entry of the size specified. */
  238. X
  239. X    register int i;
  240. X
  241. X    dprint(7, (debugfile, "prompt-for-sized-entry \"%s\" %d chars\n", 
  242. X        prompt, field_size));
  243. X
  244. X    printf("%s : ", prompt);
  245. X    
  246. X    for (i=0;i<field_size; i++)
  247. X      putchar('_');
  248. X    for (i=0;i<field_size; i++)
  249. X      putchar(BACKSPACE);
  250. X    fflush(stdout);
  251. X
  252. X    fgets(buffer, SLEN, stdin);
  253. X    no_ret(buffer);
  254. X
  255. X    if (strlen(buffer) > field_size) buffer[field_size-1] = '\0';
  256. X}
  257. SHAR_EOF
  258. echo "File src/forms.c is complete"
  259. chmod 0444 src/forms.c || echo "restore of src/forms.c fails"
  260. echo "x - extracting src/hdrconfg.c (Text)"
  261. sed 's/^X//' << 'SHAR_EOF' > src/hdrconfg.c &&
  262. X
  263. Xstatic char rcsid[] = "@(#)$Id: hdrconfg.c,v 2.12 89/03/25 21:46:24 syd Exp $";
  264. X
  265. X/*******************************************************************************
  266. X *  The Elm Mail System  -  $Revision: 2.12 $   $State: Exp $
  267. X *
  268. X *             Copyright (c) 1986, 1987 Dave Taylor
  269. X *             Copyright (c) 1988, 1989 USENET Community Trust
  270. X *******************************************************************************
  271. X * Bug reports, patches, comments, suggestions should be sent to:
  272. X *
  273. X *    Syd Weinstein, Elm Coordinator
  274. X *    elm@dsinc.UUCP            dsinc!elm
  275. X *
  276. X *******************************************************************************
  277. X * $Log:    hdrconfg.c,v $
  278. X * Revision 2.12  89/03/25  21:46:24  syd
  279. X * Initial 2.2 Release checkin
  280. X * 
  281. X *
  282. X ******************************************************************************/
  283. X
  284. X/**   This file contains the routines necessary to be able to modify
  285. X      the mail headers of messages on the way off the machine.  The
  286. X      headers currently supported for modification are:
  287. X
  288. X    Subject:
  289. X    To:
  290. X    Cc:
  291. X    Bcc:
  292. X    Reply-To:
  293. X    Expires:
  294. X    Priority:
  295. X        In-Reply-To:
  296. X    Action:
  297. X
  298. X    <user defined>
  299. X**/
  300. X
  301. X#include "headers.h"
  302. X
  303. X#include <ctype.h>
  304. X
  305. X#ifdef BSD
  306. X#undef toupper
  307. X#endif
  308. X
  309. X/* allow two lines for address-type headers, subject, and in-reply-to */
  310. X/* allow one line for all others - unlikely to exceed one line */
  311. X#define TO_LINE            2
  312. X#define CC_LINE            4
  313. X#define BCC_LINE        6
  314. X#define    SUBJECT_LINE        8
  315. X#define REPLY_TO_LINE        10
  316. X#define    ACTION_LINE        11
  317. X#define    EXPIRES_LINE        12
  318. X#define    PRIORITY_LINE        13
  319. X#define IN_REPLY_TO_LINE    14
  320. X#define USER_DEFINED_HDR_LINE    16
  321. X#define INSTRUCT_LINE        LINES-5
  322. X#define EXTRA_PROMPT_LINE    LINES-3
  323. X#define INPUT_LINE        LINES-2
  324. X#define ERROR_LINE        LINES-1
  325. X
  326. X#define put_to() {ClearLine(TO_LINE+1);\
  327. X  PutLine1(TO_LINE,0,"To: %s",expanded_to);CleartoEOLN();}
  328. X
  329. X#define put_cc() {ClearLine(CC_LINE+1);\
  330. X  PutLine1(CC_LINE,0,"Cc: %s", expanded_cc);CleartoEOLN();}
  331. X
  332. X#define put_bcc() {ClearLine(BCC_LINE+1);\
  333. X  PutLine1(BCC_LINE,0,"Bcc: %s",expanded_bcc);CleartoEOLN();}
  334. X
  335. X#define put_replyto() {PutLine1(REPLY_TO_LINE,0,"Reply-to: %s",reply_to);\
  336. X  CleartoEOLN();}
  337. X
  338. X#define put_subject() {ClearLine(SUBJECT_LINE+1);\
  339. X  PutLine1(SUBJECT_LINE,0,"Subject: %s",subject);CleartoEOLN();}
  340. X
  341. X#define put_action() {PutLine1(ACTION_LINE,0,"Action: %s",action);\
  342. X  CleartoEOLN();}
  343. X
  344. X#define put_expires() {PutLine1(EXPIRES_LINE,0,"Expires: %s",expires);\
  345. X  CleartoEOLN();}
  346. X
  347. X#define put_priority() {PutLine1(PRIORITY_LINE,0,"Priority: %s",priority);\
  348. X  CleartoEOLN();}
  349. X
  350. X#define put_inreplyto() {ClearLine(IN_REPLY_TO_LINE+1);\
  351. X  PutLine1(IN_REPLY_TO_LINE,0,"In-reply-to: %s",in_reply_to);CleartoEOLN();}
  352. X
  353. X#define put_userdefined() {PutLine1(USER_DEFINED_HDR_LINE,0,"%s",\
  354. X  user_defined_header);CleartoEOLN();}
  355. X
  356. X/* these are all defined in the mailmsg file! */
  357. Xextern char subject[SLEN], in_reply_to[SLEN], expires[SLEN], 
  358. X            action[SLEN], priority[SLEN], reply_to[SLEN], to[VERY_LONG_STRING], 
  359. X        cc[VERY_LONG_STRING], expanded_to[VERY_LONG_STRING], 
  360. X        expanded_cc[VERY_LONG_STRING], user_defined_header[SLEN],
  361. X        bcc[VERY_LONG_STRING], expanded_bcc[VERY_LONG_STRING];
  362. X
  363. Xchar *strip_commas(), *strcpy();
  364. X
  365. Xedit_headers()
  366. X{
  367. X    /** Edit headers.  **/
  368. X    int c;
  369. X
  370. X    /*  Expand address-type headers for main part of display */
  371. X    /*  (Unexpanded ones are used on the 'edit-line') */
  372. X    (void) build_address(strip_commas(to), expanded_to);
  373. X    (void) build_address(strip_commas(cc), expanded_cc);
  374. X    (void) build_address(strip_commas(bcc), expanded_bcc);
  375. X    
  376. X    display_headers();
  377. X
  378. X    clearerr(stdin);
  379. X
  380. X    clearerr(stdin);
  381. X
  382. X    while (TRUE) {    /* forever */
  383. X      PutLine0(INPUT_LINE,0,"Choice: ");
  384. X      CleartoEOS();
  385. X      c = getchar();
  386. X      c = toupper(c);
  387. X      clear_error();
  388. X      if (c == EOF)
  389. X        return(0);
  390. X      switch (c) {
  391. X        case RETURN:
  392. X        case LINE_FEED:
  393. X        case 'Q' :    return(0);
  394. X        case ctrl('L') : display_headers();
  395. X            break;
  396. X        case 'T' :    PutLine0(INPUT_LINE, 0, "To: "); CleartoEOLN();
  397. X                     if (optionally_enter(to, INPUT_LINE, 4, TRUE, FALSE) == -1)
  398. X              return(0);
  399. X            (void) build_address(strip_commas(to), expanded_to);
  400. X            put_to();
  401. X            break;
  402. X        case 'S' :    PutLine0(INPUT_LINE, 0, "Subject: "); CleartoEOLN();
  403. X                if (optionally_enter(subject,
  404. X                  INPUT_LINE, 9, FALSE, FALSE) == -1)
  405. X              return(0);
  406. X            put_subject();
  407. X            break;
  408. X        case 'B' :    PutLine0(INPUT_LINE, 0, "Bcc: "); CleartoEOLN();
  409. X                if (optionally_enter(bcc,
  410. X                  INPUT_LINE, 5, TRUE, FALSE) == -1)
  411. X              return(0);
  412. X            (void) build_address(strip_commas(bcc), expanded_bcc);
  413. X            put_bcc();
  414. X            break;
  415. X        case 'C' :    PutLine0(INPUT_LINE, 0, "Cc: "); CleartoEOLN();
  416. X                if (optionally_enter(cc, INPUT_LINE, 4, TRUE, FALSE) == -1)
  417. X              return(0);
  418. X            (void) build_address(strip_commas(cc), expanded_cc);
  419. X            put_cc();
  420. X            break;
  421. X        case 'R' :    PutLine0(INPUT_LINE, 0, "Reply-To: "); CleartoEOLN();
  422. X                if(optionally_enter(reply_to,
  423. X                  INPUT_LINE, 10, FALSE, FALSE) == -1)
  424. X              return(0);
  425. X            put_replyto();
  426. X            break;
  427. X
  428. X        case 'A' :    PutLine0(INPUT_LINE, 0, "Action: "); CleartoEOLN();
  429. X                if (optionally_enter(action,
  430. X                  INPUT_LINE, 8, FALSE, FALSE) == -1)
  431. X              return(0);
  432. X            put_action();
  433. X            break;
  434. X
  435. X        case 'P' :    PutLine0(INPUT_LINE, 0, "Priority: "); CleartoEOLN();
  436. X                if (optionally_enter(priority,
  437. X                  INPUT_LINE, 10, FALSE, FALSE)==-1)
  438. X              return(0);
  439. X            put_priority();
  440. X            break;
  441. X
  442. X        case 'E' :    enter_date(INPUT_LINE, 9, expires);
  443. X            put_expires();
  444. X            break;
  445. X
  446. X        case 'U' :    PutLine0(EXTRA_PROMPT_LINE, 0, "User defined header: ");
  447. X            CleartoEOLN();
  448. X                if (optionally_enter(user_defined_header,
  449. X                 INPUT_LINE, 0, FALSE, FALSE)==-1)
  450. X              return(0);
  451. X            check_user_header(user_defined_header);
  452. X            put_userdefined();
  453. X            ClearLine(EXTRA_PROMPT_LINE);
  454. X            break;
  455. X
  456. X        case 'I' : if (strlen(in_reply_to) > 0) {
  457. X             PutLine0(INPUT_LINE, 0, "In-Reply-To: "); CleartoEOLN();
  458. X                     if (optionally_enter(in_reply_to,
  459. X                 INPUT_LINE, 13, FALSE, FALSE) == -1)
  460. X               return(0);
  461. X             put_inreplyto();
  462. X             break;        
  463. X               }
  464. X               /** else fall through as an error **/
  465. X        default  : Centerline(ERROR_LINE, "Unknown header being specified!");
  466. X      }
  467. X    } 
  468. X}
  469. X
  470. Xdisplay_headers()
  471. X{
  472. X    ClearScreen();
  473. X
  474. X    Centerline(0,"Message Header Edit Screen");
  475. X
  476. X    put_to();
  477. X    put_cc();
  478. X    put_bcc();
  479. X    put_subject();
  480. X    put_replyto();
  481. X    put_action();
  482. X    put_expires();
  483. X    put_priority();
  484. X    if (strlen(in_reply_to) > 0) put_inreplyto();
  485. X    if (strlen(user_defined_header) > 0) put_userdefined();
  486. X
  487. X    Centerline(INSTRUCT_LINE,
  488. X"Choose first letter of existing header, u)ser defined header, or <return>.");
  489. X}
  490. X
  491. Xenter_date(x, y, datebuf)
  492. Xint x, y;
  493. Xchar *datebuf;
  494. X{
  495. X    /** Enter the number of days this message is valid for, then
  496. X        display at (x,y) the actual date of expiration.  This 
  497. X        routine relies heavily on the routine 'days_ahead()' in
  498. X        the file date.c
  499. X    **/
  500. X
  501. X    int days;
  502. X    char numdaysbuf[SLEN];
  503. X
  504. X    static char prompt[] =
  505. X      "How many days in the future should this message expire? ";
  506. X
  507. X    PutLine0(INPUT_LINE,0, prompt);
  508. X    CleartoEOLN();
  509. X    *datebuf = *numdaysbuf = '\0';
  510. X
  511. X    optionally_enter(numdaysbuf, INPUT_LINE, strlen(prompt), FALSE, FALSE);
  512. X    sscanf(numdaysbuf, "%d", &days);
  513. X    if (days < 1)
  514. X      Centerline(ERROR_LINE, "That doesn't make sense!");
  515. X    else if (days > 56)
  516. X      Centerline(ERROR_LINE, 
  517. X         "Expiration date must be within eight weeks of today.");
  518. X    else {
  519. X      days_ahead(days, datebuf);
  520. X    }
  521. X}
  522. X
  523. Xcheck_user_header(header)
  524. Xchar *header;
  525. X{
  526. X    /** check the header format...if bad print error and erase! **/
  527. X
  528. X    register int i = -1;
  529. X
  530. X    if (strlen(header) == 0)
  531. X       return;
  532. X
  533. X    if (whitespace(header[0])) {
  534. X      error ("You can't have leading white space in a header!");
  535. X      header[0] = '\0';
  536. X      ClearLine(USER_DEFINED_HDR_LINE);
  537. X      return;
  538. X    }
  539. X
  540. X    if (header[0] == ':') {
  541. X      error ("You can't have a colon as the first character!");
  542. X      header[0] = '\0';
  543. X      ClearLine(USER_DEFINED_HDR_LINE);
  544. X      return;
  545. X    }
  546. X
  547. X    while (header[++i] != ':') {
  548. X      if (header[i] == '\0') {
  549. X        Centerline(ERROR_LINE, "You need to have a colon ending the field name!");
  550. X        header[0] = '\0';
  551. X        ClearLine(USER_DEFINED_HDR_LINE);
  552. X        return;
  553. X      }
  554. X      else if (whitespace(header[i])) {
  555. X        Centerline(ERROR_LINE, "You can't have white space imbedded in the header name!");
  556. X        header[0] = '\0';
  557. X        ClearLine(USER_DEFINED_HDR_LINE);
  558. X        return;
  559. X      }
  560. X    }
  561. X    
  562. X    return;
  563. X}
  564. SHAR_EOF
  565. chmod 0444 src/hdrconfg.c || echo "restore of src/hdrconfg.c fails"
  566. echo "x - extracting src/help.c (Text)"
  567. sed 's/^X//' << 'SHAR_EOF' > src/help.c &&
  568. X
  569. Xstatic char rcsid[] = "@(#)$Id: help.c,v 2.13 89/03/25 21:46:26 syd Exp $";
  570. X
  571. X/*******************************************************************************
  572. X *  The Elm Mail System  -  $Revision: 2.13 $   $State: Exp $
  573. X *
  574. X *             Copyright (c) 1986, 1987 Dave Taylor
  575. X *             Copyright (c) 1988, 1989 USENET Community Trust
  576. X *******************************************************************************
  577. X * Bug reports, patches, comments, suggestions should be sent to:
  578. X *
  579. X *    Syd Weinstein, Elm Coordinator
  580. X *    elm@dsinc.UUCP            dsinc!elm
  581. X *
  582. X *******************************************************************************
  583. X * $Log:    help.c,v $
  584. X * Revision 2.13  89/03/25  21:46:26  syd
  585. X * Initial 2.2 Release checkin
  586. X * 
  587. X *
  588. X ******************************************************************************/
  589. X
  590. X/*** help routine for ELM program 
  591. X
  592. X***/
  593. X
  594. X#include <ctype.h>
  595. X#include "headers.h"
  596. X
  597. Xhelp(pager)
  598. Xint pager;
  599. X{
  600. X    /** Process the request for help [section] from the user.
  601. X        If pager is TRUE, then act a little differently from
  602. X        if pager is FALSE (index screen)
  603. X     **/
  604. X
  605. X    char ch;        /* character buffer for input */
  606. X    char *s;        /* string pointer...          */
  607. X    int prompt_line, info_line;
  608. X
  609. X    MoveCursor(LINES-4,0);
  610. X    CleartoEOS();
  611. X
  612. X    if(pager) {
  613. X      put_border();
  614. X      Centerline(LINES,
  615. X         "Press keys you want help for, '?' for a list, or '.' to end.");
  616. X      prompt_line = LINES-3;
  617. X    } else {
  618. X      Centerline(LINES-4, "ELM Help System");
  619. X      Centerline(LINES-3,
  620. X         "Press keys you want help for, '?' for a list, or '.' to end.");
  621. X      prompt_line = LINES-2;
  622. X    }
  623. X    info_line = prompt_line + 1;
  624. X
  625. X    PutLine0(prompt_line, 0, "Help on key: ");
  626. X
  627. X    do {
  628. X      MoveCursor(prompt_line, strlen("Help on key: "));
  629. X      ch = ReadCh();
  630. X      
  631. X      if (ch == '.') return(0);    /* zero means footer rewrite only */
  632. X
  633. X      s = "Unknown command.  Use '?' for a list of commands.";
  634. X
  635. X      switch (ch) {
  636. X
  637. X        case '?': display_helpfile(pager? PAGER_HELP : MAIN_HELP);
  638. X              return(1);
  639. X
  640. X        case '$': if(!pager) s =
  641. X"$ = Force resynchronization of the current folder. This will purge deleted mail.";
  642. X              break;
  643. X
  644. X        case '!': s = 
  645. X     "! = Escape to the Unix shell of your choice, or just to enter commands.";
  646. X                  break;
  647. X
  648. X        case '@': if(!pager) s = 
  649. X       "@ = Debug - display a summary of the messages on the header page.";
  650. X              break;
  651. X
  652. X        case '|': s = 
  653. X   "| = Pipe the current message or tagged messages to the command specified.";
  654. X              break;
  655. X
  656. X        case '#': if(!pager) s = 
  657. X        "# = Debug - display all information known about current message.";
  658. X              break;
  659. X
  660. X        case '%': s = 
  661. X     "% = Debug - display the computed return address of the current message.";
  662. X              break;
  663. X
  664. X        case '*': if(!pager)
  665. X               s = "* = Go to the last message in the current folder.";
  666. X              break;
  667. X
  668. X        case '-': if(!pager) s = 
  669. X"- = Go to the previous page of messages.  This is the same as the LEFT arrow.";
  670. X              break;
  671. X
  672. X        case '=': if(!pager) s = 
  673. X            "'=' = Go to the first message in the current folder.";
  674. X              break;
  675. X
  676. X        case ' ': if(pager) s =
  677. X  "<space> = Display next screen of current message (or first screen of next).";
  678. X              else s = "<space> = Display the current message.";
  679. X              break;
  680. X
  681. X        case '+': if(!pager)
  682. X                s = 
  683. X  "+ = Go to the next page of messages.  This is the same as the RIGHT arrow.";
  684. X              break;
  685. X
  686. X        case '/': if(!pager)
  687. X            s = "/ = Search for specified pattern in folder.";
  688. X              break;
  689. X
  690. X        case '<': s = 
  691. X           "< = Scan current message for calendar entries (if enabled).";
  692. X              break;
  693. X
  694. X        case '>': s = 
  695. X           "> = Save current message or tagged messages to specified file.";
  696. X              break;
  697. X
  698. X        case '^': if(!pager) s = 
  699. X           "^ = Toggle the Delete/Undelete status of the current message.";
  700. X              break;
  701. X
  702. X        case 'a': if(!pager) s = 
  703. X       "a = Enter the alias sub-menu section.  Create and display aliases.";
  704. X              break;
  705. X
  706. X        case 'b': s = 
  707. X      "b = Bounce (remail) a message to someone as if you have never seen it.";
  708. X              break;
  709. X
  710. X        case 'C': s = 
  711. X               "C = Copy current message or tagged messages to specified file.";
  712. X              break;
  713. X
  714. X        case 'c': if(!pager) s = 
  715. X     "c = Change folders, leaving the current folder as if 'quitting'.";
  716. X              break;
  717. X
  718. X        case 'd': s = "d = Mark the current message for future deletion.";
  719. X              break;
  720. X
  721. X        case ctrl('D') : if(!pager) s =
  722. X          "^D = Mark for deletion all messages with the specified pattern.";
  723. X              break;
  724. X
  725. X        case 'e': if(!pager) s = 
  726. X     "e = Invoke the editor on the entire folder, resynchronizing when done.";
  727. X              break;
  728. X
  729. X        case 'f': s = 
  730. X    "f = Forward the current message to someone, return address is yours.";
  731. X              break;
  732. X
  733. X        case 'g': s = 
  734. X   "g = Group reply not only to the sender, but to everyone who received msg.";
  735. X              break;
  736. X
  737. X        case 'h': s = 
  738. X         "h = Display message with all Headers (ignore weedout list).";
  739. X                  break;
  740. X
  741. X        case 'i': if(pager) s = "i = Return to the index.";
  742. X              break;
  743. X
  744. X        case 'J': s = "J = Go to the next message.";
  745. X              break;
  746. X
  747. X        case 'j': s = 
  748. X  "j = Go to the next undeleted message.  This is the same as the DOWN arrow.";
  749. X              break;
  750. X
  751. X        case 'K': s = "K = Go to the previous message.";
  752. X              break;
  753. X
  754. X        case 'k': s = 
  755. X"k = Go to the previous undeleted message.  This is the same as the UP arrow.";
  756. X              break;
  757. X
  758. X        case 'l': if(!pager) s =
  759. X               "l = Limit displayed messages based on the specified criteria.";
  760. X              break;
  761. X
  762. X        case 'm': s = 
  763. X         "m = Create and send mail to the specified person or persons.";
  764. X              break;
  765. X
  766. X        case 'n': if(pager)
  767. X            s = "n = Display the next message.";
  768. X              else
  769. X            s = 
  770. X       "n = Display the current message, then move current to next messge.";
  771. X              break;
  772. X
  773. X        case 'o': if(!pager) s = "o = Go to the options submenu.";
  774. X                  break;
  775. X
  776. X        case 'p': s = 
  777. X              "p = Print the current message or the tagged messages.";
  778. X                  break;
  779. X
  780. X        case 'q': if(pager) s = 
  781. X            "q = Quit the pager and return to the index.";
  782. X              else s =
  783. X            "q = Quit the mailer, asking about deletion, saving, etc.";
  784. X              break;
  785. X
  786. X        case 'r': s = 
  787. X"r = Reply to the message.  This only sends to the originator of the message.";
  788. X                  break;
  789. X
  790. X        case 's': s = 
  791. X               "s = Save current message or tagged messages to specified file.";
  792. X              break;
  793. X
  794. X        case 't': s = 
  795. X               "t = Tag a message for further operations (or untag if tagged).";
  796. X              break;
  797. X
  798. X        case ctrl('T') : if(!pager) s =
  799. X                "^T = Tag all messages with the specified pattern.";
  800. X              break;
  801. X
  802. X        case 'u': s =
  803. X              "u = Undelete - remove the deletion mark on the message.";
  804. X              break;
  805. X
  806. X        case 'x': s = "x = Exit the mail system quickly.";
  807. X              break;
  808. X
  809. X        case 'Q': if(!pager) s = 
  810. X        "Q = Quick quit the mailer, save read, leave unread, delete deleted.";
  811. X              break;
  812. X
  813. X        case '\n':
  814. X        case '\r': if(pager)
  815. X             s =
  816. X  "<return> = Display current message, or (builtin pager only) scroll forward.";
  817. X               else
  818. X             s = "<return> = Display the current message.";
  819. X               break;
  820. X
  821. X        case ctrl('L'): if(!pager) s = "^L = Rewrite the screen.";    
  822. X               break;
  823. X
  824. X            case ctrl('?'):                        /* DEL */
  825. X        case ctrl('Q'): if(!pager) s = "Exit the mail system quickly.";
  826. X               break;
  827. X
  828. X        default : if (isdigit(ch) && !pager) 
  829. X                s = "<number> = Make specified number the current message.";
  830. X      }
  831. X
  832. X      ClearLine(info_line);
  833. X      Centerline(info_line, s);
  834. X
  835. X    } while (ch != '.');
  836. X    
  837. X    /** we'll never actually get here, but that's okay... **/
  838. X
  839. X    return(0);
  840. X}
  841. X
  842. Xdisplay_helpfile(section)
  843. Xint section;
  844. X{
  845. X    /*** Help me!  Read file 'helpfile.<section>' and echo to screen ***/
  846. X
  847. X    char buffer[SLEN];
  848. X
  849. X    sprintf(buffer, "%s/%s.%d", helphome, helpfile, section);
  850. X    return(display_file(buffer));
  851. X}
  852. X
  853. Xdisplay_file(file)
  854. Xchar *file;
  855. X{
  856. X    /*** Display file to screen ***/
  857. X
  858. X    FILE *fileptr;
  859. X    int  lines=0;
  860. X    char buffer[SLEN];
  861. X
  862. X    if ((fileptr = fopen(file,"r")) == NULL) {
  863. X      dprint(1, (debugfile,
  864. X         "Error: Couldn't open file %s (help)\n", file));
  865. X      error1("Couldn't open file %s.",buffer);
  866. X      return(FALSE);
  867. X    }
  868. X    
  869. X    ClearScreen();
  870. X
  871. X    while (fgets(buffer, SLEN, fileptr) != NULL) {
  872. X      if (lines > LINES-3) {
  873. X        PutLine0(LINES,0,"Press <space> to continue, 'q' to return.");
  874. X        if(ReadCh() == 'q') {
  875. X          clear_error();
  876. X          fclose(fileptr);
  877. X          return(TRUE);
  878. X        }
  879. X        lines = 0;
  880. X        ClearScreen();
  881. X        Write_to_screen("%s\r", 1, buffer);
  882. X      }
  883. X      else 
  884. X        Write_to_screen("%s\r", 1, buffer);
  885. X
  886. X      lines += strlen(buffer)/COLUMNS + 1;
  887. X    }
  888. X
  889. X        PutLine0(LINES,0,"Press any key to return.");
  890. X
  891. X    (void) ReadCh();
  892. X    clear_error();
  893. X
  894. X    fclose(fileptr);
  895. X    return(TRUE);
  896. X}
  897. SHAR_EOF
  898. chmod 0444 src/help.c || echo "restore of src/help.c fails"
  899. echo "x - extracting src/in_utils.c (Text)"
  900. sed 's/^X//' << 'SHAR_EOF' > src/in_utils.c &&
  901. X
  902. Xstatic char rcsid[] = "@(#)$Id: in_utils.c,v 2.13 89/03/25 21:46:28 syd Exp $";
  903. X
  904. X/*******************************************************************************
  905. X *  The Elm Mail System  -  $Revision: 2.13 $   $State: Exp $
  906. X *
  907. X *             Copyright (c) 1986, 1987 Dave Taylor
  908. X *             Copyright (c) 1988, 1989 USENET Community Trust
  909. X *******************************************************************************
  910. X * Bug reports, patches, comments, suggestions should be sent to:
  911. X *
  912. X *    Syd Weinstein, Elm Coordinator
  913. X *    elm@dsinc.UUCP            dsinc!elm
  914. X *
  915. X *******************************************************************************
  916. X * $Log:    in_utils.c,v $
  917. X * Revision 2.13  89/03/25  21:46:28  syd
  918. X * Initial 2.2 Release checkin
  919. X * 
  920. X *
  921. X ******************************************************************************/
  922. X
  923. X/** Mindless I/O routines for ELM 
  924. X    
  925. X**/
  926. X
  927. X#include "headers.h"
  928. X#include <errno.h>
  929. X#include <ctype.h>
  930. X
  931. X#ifdef BSD
  932. X#  undef tolower
  933. X#endif
  934. X
  935. Xextern int errno;        /* system error number */
  936. X
  937. Xunsigned alarm();
  938. X
  939. X#define isstopchar(c)        (c == ' ' || c == '\t' || c == '/')
  940. X#define isslash(c)        (c == '/')
  941. X#define erase_a_char()        { Writechar(BACKSPACE); Writechar(' '); \
  942. X                      Writechar(BACKSPACE); fflush(stdout); }
  943. X
  944. Xint
  945. Xwant_to(question, dflt)
  946. Xchar *question, dflt;
  947. X{
  948. X    /** Ask 'question' on LINES-2 left enough to just leave room for an
  949. X        answer, returning the answer in lower case.
  950. X        Echo answer as full "Yes" or "No".  'dflt' is the 
  951. X        default answer if <return> is pressed. (Note: 'dflt' is also what 
  952. X        will be returned if <return> is pressed!)
  953. X    **/
  954. X    register int ch, cols;
  955. X
  956. X    cols = COLUMNS - (strlen(question) + 5 );    /* 5 for "Yes." + 1 */
  957. X
  958. X    MoveCursor(LINES-3, cols);
  959. X    CleartoEOLN();
  960. X    PutLine3(LINES-3, cols,"%s%c%c", question, dflt, BACKSPACE);
  961. X    fflush(stdout);
  962. X    fflush(stdin);
  963. X
  964. X    ch = ReadCh();
  965. X    ch = tolower(ch);
  966. X
  967. X    while (!( ch == 'y' || ch == 'n' || ch == '\n' || ch == '\r')) {
  968. X      ch = ReadCh();
  969. X      ch = tolower(ch);
  970. X    }
  971. X    if(ch == '\n' || ch == '\r')
  972. X      ch = dflt;
  973. X
  974. X    if(ch == 'y')
  975. X      Write_to_screen("Yes.", 0);
  976. X    else
  977. X      Write_to_screen("No.", 0);
  978. X
  979. X    return(ch);
  980. X}
  981. X
  982. Xint
  983. Xread_number(ch)
  984. Xchar ch;
  985. X{
  986. X    /** Read a number, where 'ch' is the leading digit! **/
  987. X    
  988. X    char buff[NLEN];
  989. X    int  num;
  990. X
  991. X    buff[0] = ch;
  992. X    buff[1] = '\0';
  993. X
  994. X    PutLine0(LINES-3, COLUMNS-40,"Set current message to :");
  995. X    if (optionally_enter(buff, LINES-3, COLUMNS-15, TRUE, FALSE) == -1)
  996. X      return(current);
  997. X
  998. X    sscanf(buff,"%d", &num);
  999. X    return(num);
  1000. X}
  1001. X
  1002. Xint
  1003. Xoptionally_enter(string, x, y, append_current, passwd)
  1004. Xchar *string;
  1005. Xint  x,y, append_current, passwd;
  1006. X{
  1007. X    /** This will display the string on the screen and allow the user to
  1008. X        either accept it (by pressing RETURN) or alter it according to
  1009. X        what the user types.   The various flags are:
  1010. X             string    is the buffer to use (with optional initial value)
  1011. X          x,y       is the location we're at on the screen (-1,-1 means
  1012. X               that we can't use this info and need to explicitly
  1013. X               use backspace-space-backspace sequences)
  1014. X         append_current  means that we have an initial string and that
  1015. X               the cursor should be placed at the END of the line,
  1016. X               not the beginning (the default).
  1017. X         passwd       accept non-printing characters and do not echo
  1018. X               entered characters.
  1019. X          
  1020. X        If we hit an interrupt or EOF we'll return non-zero.
  1021. X    **/
  1022. X
  1023. X    int ch;
  1024. X    register int ch_count = 0, iindex = 0,
  1025. X      use_cursor_control, escaped = OFF;
  1026. X
  1027. X    clearerr(stdin);
  1028. X
  1029. X    if(!passwd) {
  1030. X      if(use_cursor_control = (x >=0 && y >= 0))
  1031. X        PutLine1(x, y, "%s", string);    
  1032. X      else
  1033. X        printf("%s", string);
  1034. X    }
  1035. X
  1036. X    CleartoEOLN();
  1037. X
  1038. X    if (! append_current) {
  1039. X      if (use_cursor_control)
  1040. X        MoveCursor(x,y);
  1041. X      else if(!passwd)
  1042. X        non_destructive_back_up(strlen(string));
  1043. X    }
  1044. X    else
  1045. X      iindex = strlen(string);
  1046. X
  1047. X    if (cursor_control)
  1048. X      transmit_functions(OFF);
  1049. X
  1050. X    /** now we have the screen as we want it and the cursor in the 
  1051. X        right place, we can loop around on the input and return the
  1052. X        string as soon as the user presses <RETURN>
  1053. X    **/
  1054. X
  1055. X    do {
  1056. X      ch = getchar();
  1057. X
  1058. X      if (ch == ctrl('D') || ch == EOF) {        /* we've hit EOF */
  1059. X        if (cursor_control)
  1060. X          transmit_functions(ON);
  1061. X        return(1);
  1062. X      }
  1063. X
  1064. X      if (ch_count++ == 0) {
  1065. X        if (ch == '\n' || ch == '\r') {
  1066. X          if (cursor_control)
  1067. X            transmit_functions(ON);
  1068. X          return(0);
  1069. X        }
  1070. X        else if (! append_current) {
  1071. X          CleartoEOLN();
  1072. X          iindex = (append_current? strlen(string) : 0);
  1073. X        }
  1074. X      }
  1075. X
  1076. X      /* the following is converted from a case statement to
  1077. X         allow the variable characters (backspace, kill_line
  1078. X         and break) to be processed.  Case statements in
  1079. X         C require constants as labels, so it failed ...
  1080. X      */
  1081. X
  1082. X      if (ch == backspace &&
  1083. X        (!escaped || (ch < ' ' || ch >  '~' && !passwd))) {
  1084. X        /* This is tricky. Here we are dealing with all situations
  1085. X         * under which a backspace (really whatever erase char is
  1086. X         * set to, not necessarily \b) erases the previous character.
  1087. X         * It will erase unless escaped, because if it's escaped
  1088. X         * it is taken literally. There is one exception to that --
  1089. X         * if backspace would be rejected (we don't accept non-printing
  1090. X         * characters in non-passwd mode), we accept it here as an
  1091. X         * erasing character, for it if got rejected there would
  1092. X         * be no way of erasing a preceding backslash. */
  1093. X        escaped = OFF;
  1094. X        if (iindex > 0) {
  1095. X          if(!passwd)
  1096. X        Writechar(BACKSPACE);
  1097. X            iindex--;
  1098. X        }
  1099. X        if(!passwd) {
  1100. X          Writechar(' ');
  1101. X          Writechar(BACKSPACE);
  1102. X          fflush(stdout);
  1103. X        }
  1104. X      }
  1105. X      else if (ch == EOF || ch == '\n' || ch == '\r') {
  1106. X        escaped = OFF;
  1107. X        string[iindex] = '\0';
  1108. X        if (cursor_control)
  1109. X          transmit_functions(ON);
  1110. X        return(0);
  1111. X      }
  1112. X      else if (!passwd && ch == ctrl('W')) {    /* back up a word! */
  1113. X        escaped = OFF;
  1114. X        if (iindex == 0)
  1115. X          continue;        /* no point staying here.. */
  1116. X        iindex--;
  1117. X        if (isslash(string[iindex])) {
  1118. X          erase_a_char();
  1119. X        }
  1120. X        else {
  1121. X          while (iindex >= 0 && isspace(string[iindex])) {
  1122. X            iindex--;
  1123. X            erase_a_char();
  1124. X          }
  1125. X
  1126. X          while (iindex >= 0 && ! isstopchar(string[iindex])) {
  1127. X            iindex--;
  1128. X            erase_a_char();
  1129. X          }
  1130. X          iindex++;    /* and make sure we point at the first AVAILABLE slot */
  1131. X        }
  1132. X      }
  1133. X      else if (!passwd && ch == ctrl('R')) {
  1134. X        escaped = OFF;
  1135. X        string[iindex] = '\0';
  1136. X        if (use_cursor_control) {
  1137. X          PutLine1(x,y, "%s", string);    
  1138. X          CleartoEOLN();
  1139. X        }
  1140. X        else
  1141. X          printf("\n\r%s", string);    
  1142. X      }
  1143. X      else if (!escaped && ch == kill_line) {
  1144. X        /* needed to test if escaped since kill_line character could
  1145. X         * be a desired valid printing character */
  1146. X        escaped = OFF;
  1147. X        if(!passwd) {
  1148. X          if (use_cursor_control)
  1149. X         MoveCursor(x,y);
  1150. X          else
  1151. X         back_up(iindex);
  1152. X          CleartoEOLN();
  1153. X        }
  1154. X        iindex = 0;
  1155. X      }
  1156. X      else if (ch == '\0') {
  1157. X        escaped = OFF;
  1158. X        if (cursor_control)
  1159. X          transmit_functions(ON);
  1160. X        fflush(stdin);     /* remove extraneous chars, if any */
  1161. X        string[0] = '\0'; /* clean up string, and... */
  1162. X        return(-1);
  1163. X      }
  1164. X      else if (!passwd && (ch < ' ' || ch > '~')) {
  1165. X        /* non-printing character - warn with bell*/
  1166. X        /* don't turn off escaping backslash since current character
  1167. X         * doesn't "use it up".
  1168. X         */
  1169. X        Writechar('\007');
  1170. X      }
  1171. X      else {  /* default case */
  1172. X          if(escaped && (ch == backspace || ch == kill_line)) {
  1173. X        /* if last character was a backslash,
  1174. X         * and if this character is escapable
  1175. X         * simply write this character over it even if
  1176. X         * this character is a backslash.
  1177. X         */
  1178. X        if(!passwd)
  1179. X          Writechar(BACKSPACE);
  1180. X        iindex--;
  1181. X        string[iindex++] = ch;
  1182. X        if(!passwd)
  1183. X          Writechar(ch);
  1184. X            escaped = OFF;
  1185. X          } else {
  1186. X        string[iindex++] = ch;
  1187. X        if(!passwd)
  1188. X          Writechar(ch);
  1189. X        escaped = ( ch == '\\' ? ON : OFF);
  1190. X          }
  1191. X      }
  1192. X    } while (iindex < SLEN);
  1193. X
  1194. X    string[iindex] = '\0';
  1195. X
  1196. X    if (cursor_control)
  1197. X      transmit_functions(ON);
  1198. X
  1199. X    return(0);
  1200. X}
  1201. X
  1202. Xint
  1203. Xpattern_enter(string, alt_string, x, y, alternate_prompt)
  1204. Xchar *string, *alt_string, *alternate_prompt;
  1205. Xint  x,y;
  1206. X{
  1207. X    /** This function is functionally similar to the routine
  1208. X        optionally-enter, but if the first character pressed
  1209. X        is a '/' character, then the alternate prompt and string
  1210. X        are used rather than the normal one.  This routine 
  1211. X        returns 1 if alternate was used, 0 if not
  1212. X    **/
  1213. X
  1214. X    int ch;
  1215. X    register iindex = 0, escaped = OFF;
  1216. X
  1217. X    PutLine1(x, y, "%s", string);    
  1218. X    CleartoEOLN();
  1219. X    MoveCursor(x,y);
  1220. X
  1221. X    if (cursor_control)
  1222. X      transmit_functions(OFF);
  1223. X
  1224. X    ch = getchar();
  1225. X
  1226. X    if (ch == '\n' || ch == '\r') {
  1227. X      if (cursor_control)
  1228. X        transmit_functions(ON);
  1229. X      return(0);    /* we're done.  No change needed */
  1230. X    }
  1231. X    
  1232. X    if (ch == '/') {
  1233. X      PutLine1(x, 0, "%s", alternate_prompt);
  1234. X      CleartoEOLN();
  1235. X      (void) optionally_enter(alt_string, x, strlen(alternate_prompt)+1,
  1236. X         FALSE, FALSE);
  1237. X      return(1);
  1238. X    }
  1239. X
  1240. X    CleartoEOLN();
  1241. X
  1242. X    iindex = 0;
  1243. X
  1244. X    if (ch == kill_line) {
  1245. X      MoveCursor(x,y);
  1246. X          CleartoEOLN();
  1247. X      iindex = 0;
  1248. X    }
  1249. X    else if (ch != backspace) {
  1250. X      if(ch == '\\') escaped = ON;
  1251. X      Writechar(ch);
  1252. X      string[iindex++] = ch;
  1253. X    }
  1254. X    else if (iindex > 0) {
  1255. X      iindex--;
  1256. X      erase_a_char();
  1257. X    }
  1258. X    else {
  1259. X      Writechar(' ');
  1260. X      Writechar(BACKSPACE);
  1261. X    }
  1262. X
  1263. X    do {
  1264. X      fflush(stdout);
  1265. X      ch = getchar();
  1266. X
  1267. X      /* the following is converted from a case statement to
  1268. X         allow the variable characters (backspace, kill_line
  1269. X         and break) to be processed.  Case statements in
  1270. X         C require constants as labels, so it failed ...
  1271. X      */
  1272. X
  1273. X        if (ch == backspace &&
  1274. X          (!escaped || (ch < ' ' || ch >  '~'))) {
  1275. X          /* This is tricky. Here we are dealing with all situations
  1276. X           * under which a backspace (really whatever erase char is
  1277. X           * set to, not necessarily \b) erases the previous character.
  1278. X           * It will erase unless escaped, because if it's escaped
  1279. X           * it is taken literally. There is one exception to that --
  1280. X           * if backspace would be rejected (we don't accept non-printing
  1281. X           * characters in non-passwd mode), we accept it here as an
  1282. X           * erasing character, for it if got rejected there would
  1283. X           * be no way of erasing a preceding backslash. */
  1284. X          escaped = OFF;
  1285. X              if (iindex > 0) {
  1286. X        iindex--;
  1287. X        erase_a_char();
  1288. X          }
  1289. X          else {
  1290. X        Writechar(' ');
  1291. X        Writechar(BACKSPACE);
  1292. X          }
  1293. X        }
  1294. X        else if (ch == '\n' || ch == '\r') {
  1295. X          escaped = OFF;
  1296. X          string[iindex] = '\0';
  1297. X          if (cursor_control)
  1298. X            transmit_functions(ON);
  1299. X          return(0);
  1300. X        }
  1301. X        else if (ch == ctrl('W')) {
  1302. X          escaped = OFF;
  1303. X          if (iindex == 0)
  1304. X            continue;        /* no point staying here.. */
  1305. X          iindex--;
  1306. X          if (isslash(string[iindex])) {
  1307. X            erase_a_char();
  1308. X          }
  1309. X          else {
  1310. X            while (iindex >= 0 && isspace(string[iindex])) {
  1311. X              iindex--;
  1312. X              erase_a_char();
  1313. X            }
  1314. X
  1315. X            while (iindex >= 0 && ! isstopchar(string[iindex])) {
  1316. X              iindex--;
  1317. X              erase_a_char();
  1318. X            }
  1319. X            iindex++;/* and make sure we point at the first AVAILABLE slot */
  1320. X          }
  1321. X        }
  1322. X        else if (ch == ctrl('R')) {
  1323. X          escaped = OFF;
  1324. X          string[iindex] = '\0';
  1325. X          PutLine1(x,y, "%s", string);    
  1326. X          CleartoEOLN();
  1327. X        }
  1328. X        else if (!escaped && ch == kill_line) {
  1329. X          /* needed to test if escaped since kill_line character could
  1330. X           * be a desired valid printing character */
  1331. X          escaped = OFF;
  1332. X          MoveCursor(x,y);
  1333. X              CleartoEOLN();
  1334. X          iindex = 0;
  1335. X        }
  1336. X        else if (ch == '\0') {
  1337. X          escaped = OFF;
  1338. X          if (cursor_control)
  1339. X            transmit_functions(ON);
  1340. X          fflush(stdin);     /* remove extraneous chars, if any */
  1341. X          string[0] = '\0'; /* clean up string, and... */
  1342. X          return(-1);
  1343. X        }
  1344. X        else if (ch < ' ' || ch > '~') {
  1345. X          /* non-printing character - warn with bell*/
  1346. X          /* don't turn off escaping backslash since current character
  1347. X           * doesn't "use it up".
  1348. X           */
  1349. X          Writechar('\007');
  1350. X        }
  1351. X        else {  /* default case */
  1352. X        if(escaped && (ch == backspace || ch == kill_line)) {
  1353. X          /* if last character was a backslash,
  1354. X           * and if this character is escapable
  1355. X           * simply write this character over it even if
  1356. X           * this character is a backslash.
  1357. X           */
  1358. X          Writechar(BACKSPACE);
  1359. X          iindex--;
  1360. X          string[iindex++] = ch;
  1361. X          Writechar(ch);
  1362. X          escaped = OFF;
  1363. X        } else {
  1364. X          string[iindex++] = ch;
  1365. X          Writechar(ch);
  1366. X          escaped = ( ch == '\\' ? ON : OFF);
  1367. X        }
  1368. X        }
  1369. X    } while (iindex < SLEN);
  1370. X
  1371. X    string[iindex] = '\0';
  1372. X
  1373. X    if (cursor_control)
  1374. X      transmit_functions(ON);
  1375. X    return(0);
  1376. X}
  1377. X
  1378. Xback_up(spaces)
  1379. Xint spaces;
  1380. X{
  1381. X    /** this routine is to replace the goto x,y call for when sending
  1382. X        mail without starting the entire "elm" system up... **/
  1383. X    
  1384. X    while (spaces--) {
  1385. X      erase_a_char();
  1386. X    }
  1387. X}
  1388. X
  1389. Xnon_destructive_back_up(spaces)
  1390. Xint spaces;
  1391. X{
  1392. X    /** same as back_up() but doesn't ERASE the characters on the screen **/
  1393. X
  1394. X    while (spaces--)
  1395. X      Writechar(BACKSPACE); 
  1396. X        fflush(stdout); 
  1397. X}
  1398. X
  1399. Xint
  1400. XGetPrompt()
  1401. X{
  1402. X    /** This routine does a read/timeout for a single character.
  1403. X        The way that this is determined is that the routine to
  1404. X        read a character is called, then the "errno" is checked
  1405. X        against EINTR (interrupted call).  If they match, this
  1406. X        returns NO_OP_COMMAND otherwise it returns the normal
  1407. X        command.    
  1408. X    **/
  1409. X
  1410. X    int ch;
  1411. X
  1412. X    if (timeout > 0) {
  1413. X      alarm((unsigned) timeout);
  1414. X      errno = 0;    /* we actually have to do this.  *sigh*  */
  1415. X      ch = ReadCh();
  1416. X      if (errno == EINTR) ch = NO_OP_COMMAND;
  1417. X      alarm((unsigned) 0);
  1418. X    }
  1419. X    else
  1420. X      ch = ReadCh();
  1421. X
  1422. X    return(ch);
  1423. X}
  1424. SHAR_EOF
  1425. chmod 0444 src/in_utils.c || echo "restore of src/in_utils.c fails"
  1426. echo "x - extracting src/init.c (Text)"
  1427. sed 's/^X//' << 'SHAR_EOF' > src/init.c &&
  1428. X
  1429. Xstatic char rcsid[] = "@(#)$Id: init.c,v 2.24 89/03/25 21:46:31 syd Exp $";
  1430. X
  1431. X/*******************************************************************************
  1432. X *  The Elm Mail System  -  $Revision: 2.24 $   $State: Exp $
  1433. X *
  1434. X *             Copyright (c) 1986, 1987 Dave Taylor
  1435. X *             Copyright (c) 1988, 1989 USENET Community Trust
  1436. X *******************************************************************************
  1437. X * Bug reports, patches, comments, suggestions should be sent to:
  1438. X *
  1439. X *    Syd Weinstein, Elm Coordinator
  1440. X *    elm@dsinc.UUCP            dsinc!elm
  1441. X *
  1442. X *******************************************************************************
  1443. X * $Log:    init.c,v $
  1444. X * Revision 2.24  89/03/25  21:46:31  syd
  1445. X * Initial 2.2 Release checkin
  1446. X * 
  1447. X *
  1448. X ******************************************************************************/
  1449. X
  1450. X/***** Initialize - read in all the defaults etc etc 
  1451. X*****/
  1452. X
  1453. X#include "headers.h"
  1454. X#include "patchlevel.h"
  1455. X
  1456. X#ifdef BSD
  1457. X#  include <sgtty.h>
  1458. X#else
  1459. X#  include <termio.h>
  1460. X#endif
  1461. X
  1462. X#include <pwd.h>
  1463. X
  1464. X#ifdef BSD
  1465. X#  include <sys/time.h>
  1466. X#else
  1467. X#  include <time.h>
  1468. X#endif
  1469. X
  1470. X#include <signal.h>
  1471. X#include <ctype.h>
  1472. X#include <errno.h>
  1473. X
  1474. X#ifdef BSD
  1475. X#undef toupper
  1476. X#undef tolower
  1477. X#endif
  1478. X
  1479. Xextern int errno;        /* system error number on failure */
  1480. Xextern char version_buff[];
  1481. X
  1482. Xchar *error_name(), *error_description();
  1483. X
  1484. Xchar *getenv(), *getlogin(), *strcpy(), *strcat();
  1485. Xunsigned short getgid(), getuid(); 
  1486. Xvoid exit();
  1487. X
  1488. Xinitialize(requestedmfile)
  1489. Xchar *requestedmfile;    /* first mail file to open, empty if the default */
  1490. X{
  1491. X    /** initialize the whole ball of wax.
  1492. X    **/
  1493. X    struct passwd *pass, *getpwuid();
  1494. X    char *getenv(), *get_full_name();
  1495. X
  1496. X    register int i, j; 
  1497. X#ifdef VOIDSIG
  1498. X    void     quit_signal(), term_signal(), ill_signal(),
  1499. X         fpe_signal(),  bus_signal(),  segv_signal(),
  1500. X             alarm_signal(), pipe_signal(), hup_signal();
  1501. X#else
  1502. X    int      quit_signal(), term_signal(), ill_signal(),
  1503. X         fpe_signal(),  bus_signal(),  segv_signal(),
  1504. X             alarm_signal(), pipe_signal(), hup_signal();
  1505. X#endif
  1506. X#ifdef SIGTSTP
  1507. X#ifdef VOIDSIG
  1508. X    int sig_user_stop(), sig_return_from_user_stop();
  1509. X#else
  1510. X    int sig_user_stop(), sig_return_from_user_stop();
  1511. X#endif
  1512. X#endif
  1513. X    char     buffer[SLEN], *cp;
  1514. X
  1515. X    sprintf(version_buff, "%s PL%d", VERSION, PATCHLEVEL);
  1516. X    Raw(ON);
  1517. X
  1518. X    userid  = getuid();
  1519. X    groupid = getgid();    
  1520. X
  1521. X    (void)umask(077);    /* make all newly created files private */
  1522. X
  1523. X    /* Get username (logname), home (login directory), and full_username
  1524. X     * (part of GCOS) field from the password entry for this user id.
  1525. X     * Full_username will get overridden by fullname in elmrc, if defined.
  1526. X     */
  1527. X
  1528. X    if((pass = getpwuid(userid)) == NULL) {
  1529. X      error("You have no password entry!");
  1530. X      Raw(OFF);
  1531. X      exit(1);
  1532. X    }
  1533. X    strcpy(username, pass->pw_name);
  1534. X    strcpy(home, pass->pw_dir);
  1535. X
  1536. X    if((cp = get_full_name(username)) != NULL)
  1537. X      strcpy(full_username, cp);
  1538. X    else
  1539. X      strcpy(full_username, username);    /* fall back on logname */
  1540. X
  1541. X#ifdef DEBUG
  1542. X    if (debug) {        /* setup for dprint() statements! */
  1543. X      char newfname[SLEN], filename[SLEN];
  1544. X
  1545. X      sprintf(filename, "%s/%s", home, DEBUGFILE);
  1546. X      if (access(filename, ACCESS_EXISTS) == 0) {    /* already one! */
  1547. X        sprintf(newfname,"%s/%s", home, OLDEBUG);
  1548. X        (void) rename(filename, newfname);
  1549. X      }
  1550. X
  1551. X      /* Note what we just did up there: we always save the old
  1552. X         version of the debug file as OLDEBUG, so users can mail
  1553. X         copies of bug files without trashing 'em by starting up
  1554. X         the mailer.  Dumb, subtle, but easy enough to do!
  1555. X       */
  1556. X
  1557. X      if ((debugfile = fopen(filename, "w")) == NULL) {
  1558. X        debug = 0;    /* otherwise 'leave' will try to log! */
  1559. X        leave(fprintf(stderr,"Could not open file %s for debug output!\n",
  1560. X          filename));
  1561. X      }
  1562. X      chown(filename, userid, groupid); /* file owned by user */
  1563. X
  1564. X      fprintf(debugfile, 
  1565. X     "Debug output of the ELM program (at debug level %d).  Version %s\n\n",
  1566. X          debug, version_buff);
  1567. X    }
  1568. X#endif
  1569. X
  1570. X    if(!check_only && !batch_only) {
  1571. X      if ((i = InitScreen()) < 0) {
  1572. X        if (i == -1) {
  1573. X          printf( 
  1574. X"Sorry, but you must specify what type of terminal you're on if you want to\n");
  1575. X          printf( 
  1576. X"run the \"elm\" program. (You need your environment variable \"TERM\" set.)\n"
  1577. X             );
  1578. X          dprint(1,(debugfile,"No $TERM variable in environment!\n"));
  1579. X        }
  1580. X        else if (i == -2) {
  1581. X          printf(
  1582. X"You need a cursor-addressable terminal to run \"elm\" and I can't find any\n");
  1583. X          printf(
  1584. X"kind of termcap entry for \"%s\" - check your \"TERM\" setting...\n",
  1585. X           getenv("TERM"));
  1586. X          dprint(1,
  1587. X        (debugfile,"$TERM variable is an unknown terminal type!\n"));
  1588. X        } else {
  1589. X          printf("Failed trying to initialize your terminal entry: unknown return code %d\n", i);
  1590. X          dprint(1, (debugfile, "Initscreen returned unknown code: %d\n",
  1591. X          i));
  1592. X        }
  1593. X        Raw(OFF);
  1594. X        exit(1);    /* all the errors share this exit statement */
  1595. X      }
  1596. X    }
  1597. X
  1598. X    if (debug < 5) {    /* otherwise let the system trap 'em! */
  1599. X      signal(SIGINT,  SIG_IGN);
  1600. X      signal(SIGQUIT, quit_signal);        /* Quit signal                 */
  1601. X      signal(SIGTERM, term_signal);     /* Terminate signal         */
  1602. X      signal(SIGILL,  ill_signal);        /* Illegal instruction      */
  1603. X      signal(SIGFPE,  fpe_signal);        /* Floating point exception */
  1604. X      signal(SIGBUS,  bus_signal);        /* Bus error              */
  1605. X      signal(SIGSEGV, segv_signal);        /* Segmentation Violation   */
  1606. X      signal(SIGHUP,  hup_signal);        /* HangUp (line dropped)    */
  1607. X    }
  1608. X    else {
  1609. X      dprint(3,(debugfile,
  1610. X  "\n*** Elm-Internal Signal Handlers Disabled due to debug level %d ***\n\n",
  1611. X            debug));
  1612. X    }
  1613. X    
  1614. X    signal(SIGALRM, alarm_signal);        /* Process Timer Alarm        */
  1615. X    signal(SIGPIPE, pipe_signal);        /* Illegal Pipe Operation   */
  1616. X#ifdef SIGTSTP
  1617. X    signal(SIGTSTP, sig_user_stop);        /* Suspend signal from tty  */
  1618. X    signal(SIGCONT, sig_return_from_user_stop);    /* Continue Process */
  1619. X#endif
  1620. X
  1621. X    get_term_chars();
  1622. X    
  1623. X#ifdef HOSTCOMPILED
  1624. X    strncpy(hostname, HOSTNAME, sizeof(hostname));
  1625. X#else
  1626. X    gethostname(hostname, sizeof(hostname));
  1627. X#endif
  1628. X    gethostdomain(hostdomain, sizeof(hostdomain));
  1629. X
  1630. X    /* Determine the default mail file name.
  1631. X     * 
  1632. X     * First look for an environment variable MAIL, then
  1633. X     * use then mailhome if it is not found
  1634. X     */
  1635. X    if ((cp = getenv("MAIL")) == NULL)
  1636. X        sprintf(defaultfile, "%s%s", mailhome, username);
  1637. X    else
  1638. X        strcpy(defaultfile, cp);
  1639. X
  1640. X    /* Determine options that might be set in the .elm/elmrc */
  1641. X    read_rc_file();
  1642. X
  1643. X    /* Determine the mail file to read */
  1644. X    if (*requestedmfile == '\0')
  1645. X      strcpy(requestedmfile, defaultfile);
  1646. X    else if(!expand_filename(requestedmfile, FALSE)) {
  1647. X        Raw(OFF);
  1648. X        exit(0);
  1649. X        }
  1650. X    if (check_size)
  1651. X      if(check_mailfile_size(requestedmfile) != 0) {
  1652. X          Raw(OFF);
  1653. X          exit(0);
  1654. X      }
  1655. X
  1656. X    /* check for permissions only if not default mail file */
  1657. X    if(strcmp(requestedmfile, defaultfile) != 0) {
  1658. X      if ((errno = can_access(requestedmfile, READ_ACCESS))) {
  1659. X        dprint(1, (debugfile,
  1660. X          "Error: given file %s as folder - unreadable (%s)!\n", 
  1661. X          requestedmfile, error_name(errno)));
  1662. X        fprintf(stderr,"Can't open folder '%s' for reading!\n",
  1663. X              requestedmfile);
  1664. X        Raw(OFF);
  1665. X        exit(1);
  1666. X      }
  1667. X    }
  1668. X
  1669. X    /** check to see if the user has defined a LINES or COLUMNS
  1670. X        value different to that in the termcap entry (for
  1671. X        windowing systems, of course!) **/
  1672. X
  1673. X    ScreenSize(&LINES, &COLUMNS);
  1674. X
  1675. X    if ((cp = getenv("LINES")) != NULL && isdigit(*cp)) {
  1676. X      sscanf(cp, "%d", &LINES);
  1677. X      LINES -= 1;    /* kludge for HP Window system? ... */
  1678. X    }
  1679. X
  1680. X    if ((cp = getenv("COLUMNS")) != NULL && isdigit(*cp))
  1681. X      sscanf(cp, "%d", &COLUMNS);
  1682. X
  1683. X    /** fix the shell if needed **/
  1684. X
  1685. X    if (shell[0] != '/') {
  1686. X       sprintf(buffer, "/bin/%s", shell);
  1687. X       strcpy(shell, buffer);
  1688. X    }
  1689. X
  1690. X    if (! mail_only && ! check_only) {
  1691. X
  1692. X      /* get the cursor control keys... */
  1693. X
  1694. X      cursor_control = FALSE;
  1695. X
  1696. X      if ((cp = return_value_of("ku")) != NULL) {
  1697. X        strcpy(up, cp);
  1698. X        if ((cp = return_value_of("kd")) != NULL) {
  1699. X          strcpy(down, cp);
  1700. X          if ((cp = return_value_of("kl")) != NULL) {
  1701. X        strcpy(left, cp);
  1702. X        if ((cp = return_value_of("kr")) != NULL) {
  1703. X          strcpy(right, cp);
  1704. X          cursor_control = TRUE;
  1705. X          transmit_functions(ON);
  1706. X        }
  1707. X          }
  1708. X        }
  1709. X      }
  1710. X
  1711. X      strcpy(start_highlight, "->");
  1712. X      end_highlight[0] = '\0';
  1713. X
  1714. X      if (!arrow_cursor) {    /* try to use inverse bar instead */
  1715. X        if ((cp = return_value_of("so")) != NULL) {
  1716. X          strcpy(start_highlight, cp);
  1717. X          if ((cp = return_value_of("se")) == NULL)
  1718. X            strcpy(start_highlight, "->");
  1719. X          else {
  1720. X            strcpy(end_highlight, cp);
  1721. X            has_highlighting = TRUE;
  1722. X          }
  1723. X        }
  1724. X      }
  1725. X    }
  1726. X
  1727. X    /** clear the screen **/
  1728. X    if(!check_only && !batch_only)
  1729. X      ClearScreen();
  1730. X
  1731. X    if (! mail_only && ! check_only) {
  1732. X      if (mini_menu)
  1733. X        headers_per_page = LINES - 13;
  1734. X      else
  1735. X        headers_per_page = LINES -  8;    /* 5 more headers! */
  1736. X
  1737. X      newmbox(requestedmfile, FALSE);    /* read in the folder! */
  1738. X    }
  1739. X
  1740. X#ifdef DEBUG
  1741. X    if (debug >= 2 && debug < 10) {
  1742. X      fprintf(debugfile,
  1743. X"hostname = %-20s \tusername = %-20s \tfullname = %-20s\n",
  1744. X             hostname, username, full_username);
  1745. X
  1746. X      fprintf(debugfile,
  1747. X"home     = %-20s \teditor   = %-20s \trecvd_mail  = %-20s\n",
  1748. X         home, editor, recvd_mail);
  1749. X
  1750. X      fprintf(debugfile,
  1751. X"cur_folder   = %-20s \tfolders  = %-20s \tprintout = %-20s\n",
  1752. X         cur_folder, folders, printout);
  1753. X    
  1754. X      fprintf(debugfile,
  1755. X"sent_mail = %-20s \tprefix   = %-20s \tshell    = %-20s\n\n",
  1756. X        sent_mail, prefixchars, shell);
  1757. X    
  1758. X      if (local_signature[0])
  1759. X        fprintf(debugfile, "local_signature = \"%s\"\n",
  1760. X            local_signature);
  1761. X      if (remote_signature[0])
  1762. X        fprintf(debugfile, "remote_signature = \"%s\"\n",
  1763. X            remote_signature);
  1764. X      if (local_signature[0] || remote_signature[0])
  1765. X        fprintf(debugfile, "\n");
  1766. X    }
  1767. X#endif
  1768. X}
  1769. X
  1770. Xget_term_chars()
  1771. X{
  1772. X    /** This routine sucks out the special terminal characters
  1773. X        ERASE and KILL for use in the input routine.  The meaning 
  1774. X            of the characters are (dare I say it?) fairly obvious... **/
  1775. X
  1776. X#ifdef BSD
  1777. X    struct sgttyb term_buffer;
  1778. X
  1779. X# define TCGETA    TIOCGETP
  1780. X
  1781. X#else 
  1782. X    struct termio term_buffer;
  1783. X#endif
  1784. X
  1785. X    if (ioctl(STANDARD_INPUT, TCGETA, &term_buffer) == -1) {
  1786. X      dprint(1, (debugfile,
  1787. X           "Error: %s encountered on ioctl call (get_term_chars)\n", 
  1788. X           error_name(errno)));
  1789. X      /* set to defaults for terminal driver */
  1790. X      backspace = BACKSPACE;
  1791. X      kill_line = ctrl('U');
  1792. X    }
  1793. X    else {
  1794. X#ifdef BSD
  1795. X      backspace = term_buffer.sg_erase;
  1796. X      kill_line = term_buffer.sg_kill;
  1797. X#else
  1798. X      backspace = term_buffer.c_cc[VERASE];
  1799. X      kill_line = term_buffer.c_cc[VKILL];
  1800. X#endif
  1801. X    }
  1802. X}
  1803. SHAR_EOF
  1804. chmod 0444 src/init.c || echo "restore of src/init.c fails"
  1805. echo "x - extracting src/leavembox.c (Text)"
  1806. sed 's/^X//' << 'SHAR_EOF' > src/leavembox.c &&
  1807. X
  1808. Xstatic char rcsid[] = "@(#)$Id: leavembox.c,v 2.26 89/03/25 21:46:33 syd Exp $";
  1809. X
  1810. X/*******************************************************************************
  1811. X *  The Elm Mail System  -  $Revision: 2.26 $   $State: Exp $
  1812. X *
  1813. X *             Copyright (c) 1986, 1987 Dave Taylor
  1814. X *             Copyright (c) 1988, 1989 USENET Community Trust
  1815. X *******************************************************************************
  1816. X * Bug reports, patches, comments, suggestions should be sent to:
  1817. X *
  1818. X *    Syd Weinstein, Elm Coordinator
  1819. X *    elm@dsinc.UUCP            dsinc!elm
  1820. X *
  1821. SHAR_EOF
  1822. echo "End of part 15"
  1823. echo "File src/leavembox.c is continued in part 16"
  1824. echo "16" > s2_seq_.tmp
  1825. exit 0
  1826.  
  1827.